package displacementMapFiler 
{
	import utils.UtilsIsometric;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.DisplacementMapFilterMode;
	import flash.display.BitmapDataChannel;
	import flash.geom.Point;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	
	public class DisplacementMapFilterGravity 
	{
		public var arrGravities:Array;
		
		public var displacementMap:Bitmap;
		
		public var SCALE_Y:Number = 200;
		
		public function createDisplacementFilter():DisplacementMapFilter
		{
			if(displacementMap == null){ return new DisplacementMapFilter(); }
			
			var mapBitmap:BitmapData = displacementMap.bitmapData;
			var mapPoint:Point = new Point(displacementMap.x, displacementMap.y);
			var componentX:uint      = BitmapDataChannel.BLUE;
            var componentY:uint      = BitmapDataChannel.BLUE;
            var scaleX:Number        = 1;//20;//0.5;
            var scaleY:Number        = SCALE_Y;
            var mode:String          = DisplacementMapFilterMode.CLAMP;
            var color:uint           = 0;
            var alpha:Number         = 0;
            
			return new DisplacementMapFilter(mapBitmap,
                                             mapPoint,
                                             componentX,
                                             componentY,
                                             scaleX,
                                             scaleY,
                                             mode,
                                             color,
                                             alpha);
		}
		
		public function createDisplacementMap():void
		{
			if((arrGravities == null || arrGravities.length == 0) && displacementMap != null)
			{
				displacementMap.bitmapData.dispose();
				displacementMap.parent.removeChild(displacementMap);
				displacementMap = null;
				return;
			}
			
			var sprite:Sprite = new Sprite();
			
			var shape:Shape;
			var bitmapdata:BitmapData;
			
			/*
			 * 1. рисуем для 2D
			 * 2. переводим в изометрию конкретное поле
			 * 3. цепляем на контейнер по изометрическим координатам
			 * 4. копируем все в битмапдату, с обработкой пересечений
			 */  
			var gr:DisplacementMapFilterGravityParams;
			for(var i:int=0; i<arrGravities.length; i++)
			{
				gr = arrGravities[i];
				
				shape = getShape(gr);
				
				var bmd:Bitmap = sprite.addChild(new Bitmap(new BitmapData(shape.width*2+2, shape.height+2, true, 0x00ff00))) as Bitmap;
					bmd.bitmapData.draw(shape, new Matrix(1, .5, -1, .5, shape.width + 1, shape.height/2 + 1));
					bmd.x = UtilsIsometric.xToIsoX(int(gr.x), int(gr.y)) - bmd.width/2;
					bmd.y = UtilsIsometric.yToIsoY(int(gr.x), int(gr.y)) - bmd.height/2;
			}
			var rect:Rectangle = sprite.getBounds(sprite);
			
			bitmapdata = new BitmapData(sprite.width + 2, sprite.height + 2, false, 0x80);
			
			if(false)
			{// TEST
				bitmapdata.draw(sprite, new Matrix(1,0,0,1,-rect.left + 1,-rect.top + 1));
				
				displacementMap = new Bitmap();
				displacementMap.bitmapData = bitmapdata;
				
				displacementMap.x = rect.left;
				displacementMap.y = rect.top;
			}
			else
			{// теперь надо проверять, есть ли наложения между слоями
				var child:Bitmap = sprite.getChildAt(0) as Bitmap;
				var rectChild:Rectangle = child.getBounds(sprite);
					bitmapdata.draw(child, new Matrix(1,0,0,1,rectChild.left-rect.left + 1, rectChild.top-rect.top + 1));
					
				var rectSumm:Rectangle = rectChild.clone();
					
				for(var l:int=1; l<sprite.numChildren; l++)
				{
					child = sprite.getChildAt(l) as Bitmap;
					
					rectChild = child.getBounds(sprite);
					
					var rectIntersection:Rectangle = getRectangleIntersection(rectSumm, rectChild);
					var bmdIntersection:BitmapData;
					if(rectIntersection != null)
					{
						bmdIntersection = new BitmapData(rectIntersection.width, rectIntersection.height, false, 0xff0000);
						bmdIntersection.draw(bitmapdata, new Matrix(1,0,0,1, -rectIntersection.left+rect.left, -rectIntersection.top+rect.top));
						
						bitmapdata.draw(child, new Matrix(1,0,0,1,rectChild.left-rect.left + 1, rectChild.top-rect.top + 1));
						
						var bColor:uint;
						var pColor:uint;
						
						var lengthW:int = bmdIntersection.width;
						var lengthH:int = bmdIntersection.height;
						for(var xx:int=0; xx<lengthW; xx++)
						{
							for(var yy:int=0; yy<lengthH; yy++)
							{
								pColor = bitmapdata.getPixel(xx+rectIntersection.left-rect.left, yy+rectIntersection.top-rect.top);
								bColor = bmdIntersection.getPixel(xx, yy);
								bitmapdata.setPixel(xx+rectIntersection.x-rect.left, yy+rectIntersection.y-rect.top, ( pColor > bColor ? bColor : pColor ));
							}
						}						
					}					
					rectSumm = rectSumm.union(rectChild);
				}
				
				displacementMap = new Bitmap();
				displacementMap.bitmapData = bitmapdata;
				
				displacementMap.x = rect.left;
				displacementMap.y = rect.top;
			}
		}
		private function getShape(gr:DisplacementMapFilterGravityParams):Shape
		{
			var shape:Shape = new Shape();
			var g:Graphics = shape.graphics;
			var color:uint;			
			var radius:int = gr.radius;
			// TODO поэкспериментировать с отношением "глубины" к радиусу (т.е. чтоб яма была тем больше, чем больше её радиус)
			var deep:int = 10000/radius;
			
			for(var r:Number=radius-1; r>-1; r--)
			{
				color = gr.func(r, deep, 0x80-deep, radius-1);				
				
				g.beginFill(color);
				g.drawCircle(0, 0, r);
				g.endFill();
			}
			
			return shape;
		}		
		private function getRectangleIntersection(r1:Rectangle, r2:Rectangle):Rectangle
		{
			var r3:Rectangle = new Rectangle();
			
			r3.left = r1.left > r2.left ? r1.left : r2.left;
			r3.right = r1.right < r2.right ? r1.right : r2.right;
			r3.top = r1.top > r2.top ? r1.top : r2.top;
			r3.bottom = r1.bottom < r2.bottom ? r1.bottom : r2.bottom;
			
			switch(true)
			{
				case r3.left > r3.right || r3.top > r3.bottom:
					r3 = null;
				break;
				case r3.left == r3.right || r3.left == r3.bottom:
					r3 = null;
				break;
			}
			
			return r3;
		}
	}
}